﻿<script setup lang="ts" name="EncryptDecode">
import useScrollPosition from '@/hooks/scrollPosition'
import useScrollListener from '@/hooks/scrollListener'
import { storeToRefs } from 'pinia'
import { useSystemConfigStore } from '@/store/storage/systemConfigStore'
import Tool, { getKeyAES, md5, getRsaKeys, encodeAES, decodeAES, encodeRSA, decodeRSA, resultType } from '@/utils/aesRsa'
import { errorMessage } from '@/utils/message'
const route = useRoute()
const systemConfigStore = useSystemConfigStore()
const { systemConfig } = storeToRefs(systemConfigStore)

// 滚动行为
useScrollPosition(route)

// 滚动监听事件
useScrollListener(route)

// js生成随机字符串
const formResult1 = reactive({
  privateKey: ''
})
const onSubmit = () => {
  formResult1.privateKey = getKeyAES()
}

// md5加密截取16位字符串
const formResult2 = reactive({
  data: 'i love you',
  privateKey: ''
})
const md5Submit = () => { // 这里MD5加密加盐，盐是一个16位随机字符串
  formResult2.privateKey = md5(formResult2.data, getKeyAES(), 16)
}

// RSA生成公钥、私钥
const formResult3 = reactive({
  publicKey: '',
  privateKey: ''
})
// 公钥私钥生成的回调函数
const returnRsaKey = (privateKey, publicKey) => {
  formResult3.publicKey = publicKey
  formResult3.privateKey = privateKey
}
const rsaKeySubmit = () => {
  getRsaKeys(returnRsaKey)
}

// AES加密、解密
const formResult4 = reactive({
  data: 'i love you',
  encodeData: '',
  deCodeData: ''
})
const aesEncode = () => {
  if (formResult1.privateKey === '') {
    errorMessage('请先生成随机字符串作为私钥')
    return
  }
  if (formResult2.privateKey === '') {
    errorMessage('请先生成MD5加密字符串作为加密初始化向量')
    return
  }
  if (formResult4.data === '') {
    errorMessage('要加密的数据不能为空')
    return
  }
  formResult4.encodeData = encodeAES(formResult4.data, formResult1.privateKey, formResult2.privateKey)
}
const aesDecode = () => {
  if (formResult1.privateKey === '') {
    errorMessage('请先生成随机字符串作为私钥')
    return
  }
  if (formResult2.privateKey === '') {
    errorMessage('请先生成MD5加密字符串作为加密初始化向量')
    return
  }
  if (formResult4.encodeData === '') {
    errorMessage('要解密的数据不能为空')
    return
  }
  formResult4.deCodeData = decodeAES(formResult4.encodeData, formResult1.privateKey, formResult2.privateKey)
}

// RSA加密、解密
type formResult5Type = {
  data: string,
  encodeData: string,
  deCodeData: string,
}
const formResult5: formResult5Type = reactive({
  data: 'i love you',
  encodeData: '',
  deCodeData: ''
})
const rsaEncode = () => {
  if (formResult3.publicKey === '') {
    errorMessage('请先生成RSA公钥')
    return
  }
  if (formResult5.data === '') {
    errorMessage('要加密的数据不能为空')
    return
  }
  const encodeData = encodeRSA(formResult5.data, formResult3.publicKey)
  formResult5.encodeData = typeof encodeData === 'boolean' ? '' : encodeData
}
const rsaDecode = () => {
  if (formResult3.privateKey === '') {
    errorMessage('请先生成RSA私钥')
    return
  }
  if (formResult5.encodeData === '') {
    errorMessage('要解密的数据不能为空')
    return
  }
  const deCodeData = decodeRSA(formResult5.encodeData, formResult3.privateKey)
  formResult5.deCodeData = typeof deCodeData === 'boolean' ? '' : deCodeData
}

// RSA+AES加密、解密
type formResult6Type = {
  data: string,
  encodeData: string,
  deCodeData: string,
}
const formResult6: formResult6Type = reactive({
  data: 'i love you',
  encodeData: '',
  deCodeData: ''
})
// 后端接收到的加密数据
const enCodeData = ref<resultType>()
const aesRsaEncode = () => {
  Tool.AES_KEY = getKeyAES()
  // 这里前后端约定签名混入的私钥的生成规则，用AES密钥经过两次MD5加密，生成签名混入的私钥，这里加盐需要前后端约定为一个固定值，不可再是随机数，否则前后端生成的签名私钥将不一致。
  Tool.secret = md5(md5(Tool.AES_KEY, ''), '')
  Tool.iv = md5(Tool.AES_KEY, '', 16) // 初始向量的生成方式需要与解密时的生成方式一致
  Tool.RSA_PUBLIC_KEY = formResult3.publicKey
  if (formResult3.publicKey === '') {
    errorMessage('请先生成RSA公钥')
    return
  }
  if (formResult6.data === '') {
    errorMessage('要加密的数据不能为空')
    return
  }
  enCodeData.value = Tool.encode(formResult6.data)
  console.log(enCodeData.value, '加密后的数据')
  // formResult6.encodeData = enCodeData.value.toString();
}
const aesRsaDecode = () => {
  if (formResult3.privateKey === '') {
    errorMessage('请先生成RSA私钥')
    return
  }
  formResult6.deCodeData = Tool.decode(enCodeData.value, formResult3.privateKey)
}
</script>
<template>
  <el-space :size="systemConfig.space" fill>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>js实现生成随机16位字符串</span>
            </div>
          </template>
          <el-form :inline="true">
            <el-form-item style="flex: 1;"><el-input v-model="formResult1.privateKey" readonly placeholder="请点击右侧按钮" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="onSubmit">生成随机字符串</el-button></el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>MD5生成加密数据</span>
            </div>
          </template>
          <el-form :inline="true">
            <el-form-item style="flex: 1;"><el-input v-model="formResult2.data" placeholder="请输入要加密的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="md5Submit">加密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult2.privateKey" placeholder="加密后的内容" /></el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>前端生成RSA加密的密钥对</span>
              <el-button style="float: right;margin-top: -6px;" type="primary" icon="Check" @click="rsaKeySubmit">生成密钥对</el-button>
            </div>
          </template>
          <el-alert style="width: auto;margin: 6px 0;" title="前端生成RSA密钥对的方法仅支持HTTPS、localhost、127.0.0.1这三种可信地址，如果开发环境使用本机ip运行项目，这里是无法正常生成密钥对的。" type="warning" :closable="false" />
          <el-alert style="width: auto;margin: 12px 0;" title="RSA加密为非对称加密，需要生成公钥、私钥的密钥对，公钥加密，私钥解密，公钥是公开的，私钥私人保存，相当于密码。" type="success" :closable="false" />
          <el-form :inline="true" label-position="top">
            <el-form-item style="flex: 1;" label="公钥">
              <el-input type="textarea" v-model="formResult3.publicKey" :autosize="{ minRows: 30, maxRows: 30 }" readonly resize="none" placeholder="公钥一般用于信息加密" />
            </el-form-item>
            <el-form-item style="flex: 1;" label="私钥">
              <el-input type="textarea" v-model="formResult3.privateKey" :autosize="{ minRows: 30, maxRows: 30 }" readonly resize="none" placeholder="私钥一般用于信息解密" />
            </el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>AES加密解密</span>
            </div>
          </template>
          <el-alert
            style="width: auto;margin: 12px 0;"
            title="AES加密解密用的是同一个密钥，初始向量加密解密也需要是同一个，加密前，需在上面先生成js随机字符串，用来做AES的加密密钥，用MD5生成加密16位字符串，用来做初始向量，正常项目中使用需要事先生成保存在项目文件中。"
            type="success"
            :closable="false" />
          <el-form :inline="true">
            <el-form-item style="flex: 1;"><el-input v-model="formResult4.data" placeholder="请输入要加密的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="aesEncode">加密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult4.encodeData" readonly placeholder="加密后的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="aesDecode">解密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult4.deCodeData" readonly placeholder="解密后的内容" /></el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>RSA加密解密</span>
            </div>
          </template>
          <el-alert style="width: auto;margin: 12px 0;" title="RSA加密使用公钥，解密使用私钥，使用场景一般为前端向后端发起请求时，为请求数据加密，防止在请求过程中被拦截篡改；正常项目中使用需要后端生成密钥对，公钥发给前端，私钥后端自己保存。" type="success" :closable="false" />
          <el-form :inline="true">
            <el-form-item style="flex: 1;"><el-input v-model="formResult5.data" placeholder="请输入要加密的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="rsaEncode">加密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult5.encodeData" readonly placeholder="加密后的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="rsaDecode">解密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult5.deCodeData" readonly placeholder="解密后的内容" /></el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="systemConfig.space">
      <el-col>
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>AES加密数据，RSA加密AES密钥，SHA256做签名</span>
            </div>
          </template>
          <el-alert
            style="width: auto;margin: 12px 0;"
            title="RSA加密数据有长度限制，可以使用AES密钥加密数据，然后使用RSA的公钥加密AES的密钥，后端使用RSA的私钥解密AES的密钥，再用AES密钥解密数据，加密的同时可以混入一个前后端约定好的密钥，用来做签名，前端将约定密钥、加密数据、加密AES密钥数据、当前时间戳数据组装成数据对象，并对数据对象使用SHA256做签名操作，将签名也放入该数据对象内，并删除数据对象内的约定密钥，将该数据对象传递给后端，后端验签则拿自己保存的约定密钥和前端传递的数据对象中的加密数据、加密AES密钥数据、当前时间戳数据整体进行签名，比对是否与前端传递过来的签名一致。一致则说明数据无篡改，再做解密AES密钥，用AES密钥解密数据这些后续操作。这种方式的加密每次数据加密的密钥都可以是随机的，因为AES密钥是经过RSA加密发送给了后端，每次传递数据，都可以是一个新的AES密钥"
            type="success"
            :closable="false" />
          <el-form :inline="true">
            <el-form-item style="flex: 1;"><el-input v-model="formResult6.data" placeholder="请输入要加密的内容" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="aesRsaEncode">加密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult6.encodeData" readonly placeholder="加密后的内容请看控制台打印结果" /></el-form-item>
            <el-form-item><el-button type="primary" icon="Check" @click="aesRsaDecode">解密</el-button></el-form-item>
            <el-form-item style="flex: 1;"><el-input v-model="formResult6.deCodeData" readonly placeholder="解密后的内容" /></el-form-item>
          </el-form>
        </el-card>
      </el-col>
    </el-row>
  </el-space>
</template>

<style scoped lang="scss">
.el-space {
  display: block;
  width: 100%;
  padding: var(--el-space) var(--el-space) 0;
}

.el-form {
  display: flex;
}
</style>
